// Copyright (c) 2024 刻BITTER
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


#pragma once

#include <algorithm>
#include <cstdint>
#include <cstdlib>

#include "./common.hpp"

namespace data_basic {

    template <typename T>
    class PtrToObject {
       private:
        T *_ptr;

       public:
        PtrToObject(T *ptr = nullptr) :
            _ptr(ptr) {}

        bool operator!=(const PtrToObject<T> &it) { return this->_ptr != it._ptr; }

        T &operator*() { return *_ptr; }

        const T &operator*() const { return *_ptr; }

        T *operator->() { return _ptr; }

        const T *operator->() const { return _ptr; }

        void swap(PtrToObject<T> &another) {
            swap(this->_ptr, another.ptr);
        }

        bool is_nullptr() const {
            return _ptr == nullptr;
        }

        const T &to_object() const {
            return *_ptr;
        }

        T &to_object() {
            return *_ptr;
        }
    };


    template <typename T>
    bool operator<(const PtrToObject<T> &left, const PtrToObject<T> &right) {
        return *left < *right;
    }


    /**
     * @brief 用来存储指向较大结构体或对象的指针，然后可以对指针排序
     *
     * 主要适用于只增不减的场合, 或一次性全部清除然后重新从头加入数据
     *
     * @tparam T
     * @tparam N
     */
    template <typename T, size_t N>
    class PointerList {
       public:
        using SizeType = enough_and_fast_index_type<N>;

       private:
        PtrToObject<T> _ptr_list[N];

        SizeType _size = 0;

       public:
        bool empty() const {
            return _size == 0;
        }

        bool not_full() const {
            return _size != N;
        }

        SizeType size() const {
            return _size;
        }

        bool max_size() const {
            return N;
        }

        void clear() {
            _size = 0;
        }

        bool push_back(T *obj) {
            if (_size < N) {
                _ptr_list[_size] = obj;
                ++_size;
                return true;
            }
            else {
                return false;
            }
        }

        void sort() {
            auto start_it = &_ptr_list[0];
            auto end_it = &_ptr_list[_size];

            std::sort(start_it, end_it);
        }

        PtrToObject<T> &back() {
            return _ptr_list[_size - 1];
        }

        const PtrToObject<T> &back() const {
            return _ptr_list[_size - 1];
        }

        PtrToObject<T> *begin() {
            return &_ptr_list[0];
        }

        PtrToObject<T> *end() {
            return &_ptr_list[_size];
        }

        const PtrToObject<T> *begin() const {
            return &_ptr_list[0];
        }

        const PtrToObject<T> *end() const {
            return &_ptr_list[_size];
        }

        auto &get_ptr_list() {
            return _ptr_list;
        }

        const auto &get_ptr_list() const {
            return _ptr_list;
        }
    };

}  // namespace data_basic
